#include "Model.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <GL/glew.h>

void mgl::Model::readFile(const std::string& path, bool regenNormal)
{
	Assimp::Importer importer;
	auto scene = importer.ReadFile(path,
		aiProcess_OptimizeMeshes|
		aiProcess_ImproveCacheLocality|
		aiProcess_Triangulate|
		aiProcess_SortByPType|
		(regenNormal?aiProcess_GenNormals:0)
		);

	m_meshes.resize(scene->mNumMeshes);

	for(uint m = 0, interMIdx = 0; m < scene->mNumMeshes; m++){
		auto mesh = scene->mMeshes[m];
		auto& interMesh = m_meshes[interMIdx++];

		interMesh.m_iBuffer.resize(mesh->mNumFaces*3);
		//process index
		for(uint f = 0, bufIdx = 0; f < mesh->mNumFaces; f++){
			auto& face = mesh->mFaces[f];
			for(int i = 0; i < 3; i++){
				assert(face.mNumIndices == 3);
				auto index = face.mIndices[i];
				interMesh.m_iBuffer[bufIdx++] = index;
			}
		}

		//process vertex
		interMesh.m_vBuffer.resize(mesh->mNumVertices*3);
		for(uint v = 0, interVIdx = 0; v < mesh->mNumVertices; v++){
			interMesh.m_vBuffer[interVIdx++] = mesh->mVertices[v].x;
			interMesh.m_vBuffer[interVIdx++] = mesh->mVertices[v].y;
			interMesh.m_vBuffer[interVIdx++] = mesh->mVertices[v].z;
		}

		//process normal
		interMesh.m_nBuffer.resize(mesh->mNumVertices*3);
		for(uint n = 0, interNIdx = 0; n < mesh->mNumVertices; n++){
			interMesh.m_nBuffer[interNIdx++] = mesh->mNormals[n].x;
			interMesh.m_nBuffer[interNIdx++] = mesh->mNormals[n].y;
			interMesh.m_nBuffer[interNIdx++] = mesh->mNormals[n].z;
		}

		//TODO process tex coord

	}
}

void mgl::Model::createBuffer()
{
	for(auto& mesh : m_meshes)
		mesh.createBuffer();
}

void mgl::Model::releaseBuffer()
{
	for(auto& mesh : m_meshes)
		mesh.releaseBuffer();
}

void mgl::Model::draw()const
{
	for(auto& mesh : m_meshes)
		mesh.draw();
}

void mgl::Mesh::createBuffer()
{
	//index
	glGenBuffers(1, &m_iBufferId);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_iBufferId);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_iBuffer.size()*sizeof(uint), &m_iBuffer[0], GL_STATIC_DRAW);
	//vertex
	glGenBuffers(1, &m_vBufferId);
	glBindBuffer(GL_ARRAY_BUFFER, m_vBufferId);
	glBufferData(GL_ARRAY_BUFFER, m_vBuffer.size()*sizeof(float), &m_vBuffer[0], GL_STATIC_DRAW);
	//normal
	glGenBuffers(1, &m_nBufferId);
	glBindBuffer(GL_ARRAY_BUFFER, m_nBufferId);
	glBufferData(GL_ARRAY_BUFFER, m_nBuffer.size()*sizeof(float), &m_nBuffer[0], GL_STATIC_DRAW);
	//TODO tex coord

}

void mgl::Mesh::releaseBuffer()
{
	glDeleteBuffers(1, &m_iBufferId);
	glDeleteBuffers(1, &m_vBufferId);
	glDeleteBuffers(1, &m_nBufferId);
}

void mgl::Mesh::draw()const
{
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	glBindBuffer(GL_ARRAY_BUFFER, m_vBufferId);
	glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,nullptr);

	glBindBuffer(GL_ARRAY_BUFFER, m_nBufferId);
	glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,nullptr);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_iBufferId);
	glDrawElements(GL_TRIANGLES,(GLsizei)m_iBuffer.size(),GL_UNSIGNED_INT,nullptr);

	glDisableVertexAttribArray(1);
	glDisableVertexAttribArray(0);
}

void mgl::Mesh::regenNormal()
{
	for(auto i : m_iBuffer){
		
	}
}
